#include "DHT11_driver.h"        // DHT11驱动头文件
#include "hi_time.h"             // 硬件时间操作接口
#include <stdio.h>               // 标准输入输出

WifiIotGpioValue DHT11_Out;      // 存储GPIO输入值的全局变量

/**
 * @brief 设置DHT11 GPIO工作模式
 * @param mode 模式选择: 1=输出模式, 0=输入模式
 */
void DHT11_GPIO_Mode(uint8_t mode) {
    if (mode) {
        // 设置为输出模式
        GpioSetDir(DHT11_GPIO_PIN, WIFI_IOT_GPIO_DIR_OUT);
    } else {
        // 设置为输入模式
        GpioSetDir(DHT11_GPIO_PIN, WIFI_IOT_GPIO_DIR_IN);
        // 设置无上拉电阻
        IoSetPull(DHT11_GPIO_PIN, WIFI_IOT_IO_PULL_NONE);
    }
}

/**
 * @brief 读取DHT11的响应状态
 * @return GPIO输入值 (高电平或低电平)
 */
uint8_t DHT11_Rsp(void) {
    // 获取GPIO输入值并存入全局变量DHT11_Out
    GpioGetInputVal(DHT11_GPIO_PIN, &DHT11_Out);
    return DHT11_Out;
}

/**
 * @brief 复位DHT11传感器
 * 发送开始信号，准备读取数据
 */
void DHT11_Rst(void) {
    // 设置GPIO为输出模式
    DHT11_GPIO_Mode(OUT);
    
    // 发送开始信号时序
    DHT11_HIGH;              // 拉高总线
    hi_udelay(30);           // 保持30微秒
    
    DHT11_LOW;               // 拉低总线
    hi_udelay(20000);        // 保持20毫秒 (DHT11要求至少18ms)
    
    DHT11_HIGH;              // 再次拉高总线
    hi_udelay(30);           // 保持35微秒
    
    // 切换回输入模式，准备接收数据
    DHT11_GPIO_Mode(IN);
}

/**
 * @brief 检查DHT11是否存在
 * @return 1=存在, 0=不存在
 */
uint8_t DHT11_Check(void) {
    uint8_t retry = 0;
    
    // 等待DHT11拉低总线 (响应信号)
    while (DHT11_Rsp() && retry < 100) {
        retry++;
        hi_udelay(1);
    }
    
    // 超时未响应
    if (retry >= 100) return 0;
    
    retry = 0;
    // 等待DHT11拉高总线 (准备发送数据)
    while (!DHT11_Rsp() && retry < 100) {
        retry++;
        hi_udelay(1);
    }
    
    // 超时未完成准备
    if (retry >= 100) return 0;
    
    return 1;  // 成功检测到DHT11
}

/**
 * @brief 读取单个数据位
 * @return 读取到的数据位值 (0或1)
 */
uint8_t DHT11_Read_bit(void) {
    uint8_t retry = 0;
    
    // 等待总线变高 (位开始)
    while (DHT11_Rsp() && retry < 100) {
        retry++;
        hi_udelay(1);
    }
    
    retry = 0;
    // 等待总线变低 (数据位开始)
    while (!DHT11_Rsp() && retry < 100) {
        retry++;
        hi_udelay(1);
    }
    
    // 延时40微秒判断位值
    hi_udelay(40);
    
    // 40us后总线为高表示"1"，为低表示"0"
    return DHT11_Rsp() ? 1 : 0;
}

/**
 * @brief 读取一个字节的数据
 * @return 读取到的字节数据
 */
uint8_t DHT11_Read_Byte(void) {
    uint8_t Byte = 0;
    
    // 读取8位数据
    for (uint8_t i = 0; i < 8; i++) {
        Byte <<= 1;              // 左移为下一位腾出空间
        Byte |= DHT11_Read_bit(); // 读取并添加当前位
    }
    
    printf("%d Byte\n", Byte);  // 调试输出
    return Byte;
}

/**
 * @brief 读取温湿度数据
 * @param tempH 温度整数部分指针
 * @param tempL 温度小数部分指针
 * @param humiH 湿度整数部分指针
 * @param humiL 湿度小数部分指针
 */
void DHT11_Read_Data(uint8_t *tempH, uint8_t *tempL, uint8_t *humiH, uint8_t *humiL) {
    uint8_t buff[5] = {0};  // 存储读取的5字节数据
    
    // 复位传感器
    DHT11_Rst();
    
    // 检查传感器响应
    if (DHT11_Check()) {
        // 读取5个字节数据
        for (uint8_t i = 0; i < 5; i++) {
            buff[i] = DHT11_Read_Byte();
        }
        
        // 校验数据: 湿度整数+湿度小数+温度整数+温度小数 = 校验和
        if ((buff[0] + buff[1] + buff[2] + buff[3]) == buff[4]) {
            *tempH = buff[2];  // 温度整数部分
            *tempL = buff[3];  // 温度小数部分
            *humiH = buff[0];  // 湿度整数部分
            *humiL = buff[1];  // 湿度小数部分
        }
    }
}

/**
 * @brief 初始化DHT11并启动传感器
 * @return 1=初始化成功, 0=失败
 */
uint8_t DHT11_Start(void) {
    // 初始化GPIO
    GpioInit();
    
    // 设置GPIO9功能为普通GPIO
    IoSetFunc(DHT11_GPIO_PIN, WIFI_IOT_IO_FUNC_GPIO_9_GPIO);
    
    // 复位传感器
    DHT11_Rst();
    
    // 检查传感器是否存在
    return DHT11_Check();
}